#!/usr/bin/perl

open(OBJ, "$ARGV[0]") or 
  die("Error: cannot open file output\n");

$core = $ARGV[1];
$mod_start = $ARGV[2];
@lines = <OBJ>;
@names = (0);
$names_cnt = 0;
%start = (0);
%end = (0);
@dep = {0};
%dep_start = {};
%dep_end = {};
$dep_count = 0;
$double = 0;
$max_dp = 0;
$max_cp = 0;
%cp_start = {};
%cp_end = {};
@cp_calls = {};
$cp_counts = 0;
%dp_start = {};
%dp_end = {};
@dp_calls = {};
$dp_counts = 0;
$start_cp = 1;
$start_dp = 1;
for($count = 0; $count < $#lines; $count++) {
	if ($lines[$count++] =~ /\<(.+)\>\:/) {
		if ($double == 0) {
			$name = $1;
			$names[$names_cnt] = $1;
			print $names[$names_cnt],"\n";
		}
		if ($lines[$count] =~ /(0x[0-9a-f]+)/) {
			print "Calls:\n";
			$count++;
			$start{$name} = hex($1);
			$end{$name} = hex($1);
			#print $start[$names_cnt],"\n";
			$dep_start{$name} = $dep_count;
			$dp_start{$name} = $dp_count;
			$cp_start{$name} = $cp_count;
			while ($lines[$count] =~ /(0x[0-9a-f]+)/) {
				$end{$name} = hex($1);
				if ($lines[$count] =~ /cp\[(0x[0-9a-f]+)\]/) {
					$cp_calls[$cp_count] = hex($1);
					print "\t",$cp_calls[$cp_count++],"\n";
				}
				if ($lines[$count] =~ /dp\[(0x[0-9a-f]+)\]/) {
					$dp_calls[$dp_count] = hex($1);
					print "\t",$dp_calls[$dp_count++],"\n";
				}
				if ($lines[$count] =~ /set.*cp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_cp == 1) {
							print "CP: ",$1;
							$cp = 2*hex($1) + $end{$name};
							print "Real: ",$cp,"\n";
							$start_cp = 0;
						}
					}
				}
				if ($lines[$count] =~ /set.*dp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_dp == 1) {
							print "DP: ",$1;
							$dp = 2*hex($1) + $end{$name};
							print "Real: ",$dp,"\n";
							$start_dp = 0;
						}
					}
				}
				if ($lines[$count] =~ /\<([_a-zA-Z0-9]+)\>/) {
					$dep[$dep_count] = $1;
					print "\t",$dep[$dep_count++],"\n";
				}
				$count++;
			}
			print $start{$name}," ";
			print $end{$name},"\n";
			$names_cnt++;
			$dep_end{$name} = $dep_count;
			$dp_end{$name} = $dp_count;
			$cp_end{$name} = $cp_count;
			print "\n";
			$double = 0;
		} else {
			$count--;
			$double = 1;
		}

	}
}

$min = 1280000;
$max = 0;
print "Start: ",$min," End: ",$max,"\n";
print_tree($mod_start,0);

sub print_tree {
	my $name = $_[0];
	my $ind = $_[1];
	if ($end{$name} > $max) {
		$max = $end{$name};
	}
	if ($start{$name} < $min) {
		$min = $start{$name};
	}
	for (my $j = 0; $j < $ind; $j++) {
		print "\t";
	}
	print $name,"\n";
	for (my $i = $dp_start{$name}; $i < $dp_end{$name}; $i++) {
		if ($dp_calls[$i] > $max_dp) {
			$max_dp = $dp_calls[$i];
		}
	}
	for (my $i = $cp_start{$name}; $i < $cp_end{$name}; $i++) {
		if ($cp_calls[$i] > $max_cp) {
			$max_cp = $cp_calls[$i];
		}
	}
	for (my $i = $dep_start{$name}; $i < $dep_end{$name}; $i++) {
		print_tree($dep[$i],$ind+1);
	}
}
if ($max_cp*2 + $cp > $max) {
	$max = $cp + 2*$max_cp;
}
if ($max_dp*2 + $dp > $max) {
	$max = $dp + 2*$max_dp;
}
print "#define MOD_START_",$core," ",$min,"\n";
print "#define MOD_SIZE_",$core," ",($max - $min),"\n";
print "#define MOD_OFFSET_",$core," ",$start{$mod_start},"\n";
print "#define MOD_CP_",$core," ",$cp,"\n";
print "#define MOD_DP_",$core," ",$dp,"\n";
print "#define MOD_STACK_",$core," ",(0x500),"\n";